#include <queue>
#include <pthread.h>
struct data
{
    data(int val = 0)
        :val(val)
    {}
    int val;
};


std::ostream& operator<< (std::ostream& out, const data& d)
{
    out << d.val;
    return out;
}


namespace my
{
    template<class T>
    class block_queue
    {
    public:
        block_queue(size_t max_size = 1000)
            :_max_size(max_size)
        {
            pthread_mutex_init(&_mutex, nullptr);
            pthread_cond_init(&_consumer_cond, nullptr);
            pthread_cond_init(&_producer_cond, nullptr);
        }  


        bool empty() const
        {
            return _b_queue.empty();
        }


        bool full() const
        {
            return _b_queue.size() == _max_size;
        }


        //生产者
        void push(const T& data)
        {
            pthread_mutex_lock(&_mutex);    //加锁
            //循环判断以防止虚假唤醒
            while(full())
            {
                //队列满了，生产者等待
                //等待必须解锁，否则其他线程都拿不到锁
                //条件变量等待的条件一定属于临界资源，
                //所以pthread_cond_wait一定属于临界区代码
                //所以pthread_cond_wait这个函数在内部一定会解锁来防止死锁
                //被唤醒后会竞争锁
                pthread_cond_wait(&_producer_cond, &_mutex);    
            }

            _b_queue.push(data);                   //入队
            std::cout << "生产数据" << data << std::endl;
            pthread_mutex_unlock(&_mutex);         //解锁
            pthread_cond_signal(&_consumer_cond);  //唤醒消费者
            std::cout << "唤醒消费者" << std::endl;
        }


        const T& pop()
        {
            pthread_mutex_lock(&_mutex);    //加锁
            //循环判断以防止虚假唤醒
            while(empty())
            {
                pthread_cond_wait(&_consumer_cond, &_mutex);    

            }

            T& ret = _b_queue.front();
            std::cout << "消费数据" << ret << std::endl;
            _b_queue.pop();                        //出队                  
            pthread_mutex_unlock(&_mutex);         //解锁
            pthread_cond_signal(&_producer_cond);  //唤醒生产者
            std::cout << "唤醒生产者" << std::endl;
            return ret;
        }


        ~block_queue()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_consumer_cond);
            pthread_cond_destroy(&_producer_cond);
        }  

        size_t size() const
        {
            return _b_queue.size();
        }


    private:
        std::queue<T> _b_queue;            //底层容器
        size_t _max_size;                  //队列最大容量
        pthread_mutex_t _mutex;            //给队列加锁
        pthread_cond_t _consumer_cond;     //消费者条件变量
        pthread_cond_t _producer_cond;     //生产者条件变量

    };
    
}